import socket
import threading

from .data_parse import is_modbus_data, parse_modbus_rtu

# 全局变量存储客户端连接
clients = {}  # {client_address: client_socket}
client_ids = {}  # {client_id: client_address}
address_to_id = {}  # {client_address: client_id}
clients_lock = threading.Lock()
next_client_id = 1


def format_raw_data(data):
    """格式化非Modbus原始数据显示"""
    output = []
    
    # 原始数据显示
    output.append("=" * 60)
    output.append("📡 接收到原始数据")
    output.append("=" * 60)
    output.append(f"原始字节数据: {data}")
    output.append(f"十六进制格式: {data.hex().upper()}")
    output.append(f"数据长度: {len(data)} 字节")
    
    # 尝试不同的解码方式
    output.append("\n🔍 数据解析尝试:")
    output.append("-" * 40)
    
    # 尝试UTF-8解码
    try:
        utf8_text = data.decode('utf-8')
        if utf8_text.isprintable():
            output.append(f"UTF-8文本: {utf8_text}")
        else:
            output.append("UTF-8文本: 包含不可打印字符")
    except UnicodeDecodeError:
        output.append("UTF-8文本: 解码失败")
    
    # 尝试ASCII解码
    try:
        ascii_text = data.decode('ascii')
        if ascii_text.isprintable():
            output.append(f"ASCII文本: {ascii_text}")
        else:
            output.append("ASCII文本: 包含不可打印字符")
    except UnicodeDecodeError:
        output.append("ASCII文本: 解码失败")
    
    # 尝试GBK解码
    try:
        gbk_text = data.decode('gbk')
        if gbk_text.isprintable():
            output.append(f"GBK文本: {gbk_text}")
        else:
            output.append("GBK文本: 包含不可打印字符")
    except UnicodeDecodeError:
        output.append("GBK文本: 解码失败")
    
    # 显示字节值
    output.append(f"字节值: {[f'0x{b:02X}' for b in data]}")
    output.append(f"十进制值: {list(data)}")
    
    # 如果数据较短，显示二进制
    if len(data) <= 16:
        output.append(f"二进制: {' '.join(f'{b:08b}' for b in data)}")
    
    output.append("=" * 60)
    return "\n".join(output)


def format_modbus_data(data, parsed_result):
    """格式化Modbus数据显示"""
    output = []
    
    # 原始数据显示
    output.append("=" * 60)
    output.append("📡 DTU透传Modbus数据接收")
    output.append("=" * 60)
    output.append(f"原始字节数据: {data}")
    output.append(f"十六进制格式: {data.hex().upper()}")
    output.append(f"数据长度: {len(data)} 字节")
    
    # Modbus解析结果
    output.append("\n🔍 Modbus协议解析:")
    output.append("-" * 40)
    
    if "error" in parsed_result:
        output.append(f"❌ 解析失败: {parsed_result['error']}")
    else:
        output.append(f"设备地址: {parsed_result['slave_id']} (0x{parsed_result['slave_id']:02X})")
        output.append(f"功能码: {parsed_result['function_code']} (0x{parsed_result['function_code']:02X})")
        output.append(f"功能: {parsed_result['function']}")
        output.append(f"CRC校验: {'✅ 正确' if parsed_result['crc_valid'] else '❌ 错误'}")
        output.append(f"接收CRC: {parsed_result['received_crc']}")
        output.append(f"计算CRC: {parsed_result['calculated_crc']}")
        
        # 显示具体数据
        if "registers" in parsed_result:
            output.append(f"寄存器数量: {len(parsed_result['registers'])}")
            output.append("寄存器值:")
            for i, (dec_val, hex_val) in enumerate(zip(parsed_result['registers'], parsed_result['register_hex'])):
                output.append(f"  寄存器{i}: {dec_val} ({hex_val})")
                
        elif "coil_data" in parsed_result:
            output.append(f"线圈数据: {parsed_result['coil_data']}")
            
        elif "input_data" in parsed_result:
            output.append(f"输入数据: {parsed_result['input_data']}")
            
        elif "coil_address" in parsed_result:
            output.append(f"线圈地址: {parsed_result['coil_address']}")
            output.append(f"线圈值: {parsed_result['coil_value']}")
            
        elif "register_address" in parsed_result:
            output.append(f"寄存器地址: {parsed_result['register_address']}")
            output.append(f"寄存器值: {parsed_result['register_value']} ({parsed_result['register_value_hex']})")
    
    output.append("=" * 60)
    return "\n".join(output)


def cleanup_client_by_ip(client_ip):
    """清理指定IP的所有旧连接"""
    clients_to_remove = []

    # 查找所有相同IP的连接
    for addr, socket_obj in clients.items():
        if addr[0] == client_ip:  # 比较IP地址（忽略端口）
            clients_to_remove.append(addr)

    # 清理旧连接
    for addr in clients_to_remove:
        old_client_id = address_to_id.get(addr)
        old_socket = clients.get(addr)

        # 关闭旧连接
        if old_socket:
            try:
                old_socket.close()
            except:
                pass

        # 从映射中删除
        if addr in clients:
            del clients[addr]
        if old_client_id and old_client_id in client_ids:
            del client_ids[old_client_id]
        if addr in address_to_id:
            del address_to_id[addr]

        print(f"🔄 清理旧连接 [ID: {old_client_id}] {addr}")


def handle_client(client_socket, client_address):
    """处理单个客户端连接的函数"""
    global next_client_id

    # 检查并清理同一IP的旧连接
    with clients_lock:
        client_ip = client_address[0]

        # 清理同一IP的所有旧连接
        cleanup_client_by_ip(client_ip)

        # 为新客户端分配唯一ID
        client_id = next_client_id
        next_client_id += 1

        # 将客户端添加到连接列表
        clients[client_address] = client_socket
        client_ids[client_id] = client_address
        address_to_id[client_address] = client_id

    print(f"🔗 设备 {client_address} 连接成功 [ID: {client_id}]")

    try:
        while True:
            # 持续接收客户端消息（可能是DTU透传数据或其他数据）
            data = client_socket.recv(1024)
            if data:
                print(f"\n📨 收到来自 {client_address} 的数据:")

                # 判断是否为Modbus数据
                if is_modbus_data(data):
                    print("🔍 检测到Modbus RTU协议数据")
                    # 解析Modbus数据
                    parsed_result = parse_modbus_rtu(data)
                    # 格式化并显示Modbus数据
                    formatted_output = format_modbus_data(data, parsed_result)
                    print(formatted_output)
                else:
                    print("📄 检测到非Modbus数据，按原样显示")
                    # 格式化并显示原始数据
                    formatted_output = format_raw_data(data)
                    print(formatted_output)

            else:
                # 客户端断开连接
                print(f"🔌 设备 {client_address} 断开连接")
                break
    except ConnectionResetError:
        print(f"⚠️  设备 {client_address} 强制断开连接")
    except Exception as e:
        print(f"❌ 处理设备 {client_address} 时发生错误: {e}")
    finally:
        # 从连接列表中移除客户端
        with clients_lock:
            if client_address in clients:
                client_id = address_to_id.get(client_address)
                del clients[client_address]
                if client_id is not None:
                    del client_ids[client_id]
                    del address_to_id[client_address]
        client_socket.close()
        print(f"🔌 设备 {client_address} [ID: {client_id}] 连接已关闭")


def console_input_handler():
    """处理控制台输入的函数"""
    print("\n=== 智能数据采集服务端控制台 ===")
    print("输入命令:")
    print("  'list' - 查看所有连接的设备")
    print("  'send <设备ID或地址> <数据>' - 向指定设备发送数据")
    print("    - 使用设备ID: send 1 01030000000AC5CD")
    print("    - 使用设备地址: send ('127.0.0.1', 12345) 01030000000AC5CD")
    print("    - 发送文本: send 1 text:Hello")
    print("  'broadcast <数据>' - 向所有设备广播数据")
    print("  'test <设备ID或地址>' - 向指定设备发送测试Modbus读取命令")
    print("  'quit' - 退出服务器")
    print("=====================================\n")

    while True:
        try:
            command = input("服务端> ").strip()

            if not command:
                continue

            if command == 'quit':
                print("正在关闭服务器...")
                break
            elif command == 'list':
                with clients_lock:
                    if clients:
                        print("当前连接的设备:")
                        print(f"{'ID':<4} {'地址':<20} {'端口':<8} {'状态'}")
                        print("-" * 40)
                        for addr, socket_obj in clients.items():
                            client_id = address_to_id.get(addr, "未知")
                            ip, port = addr
                            status = "在线" if socket_obj else "离线"
                            print(f"{client_id:<4} {ip:<20} {port:<8} {status}")
                    else:
                        print("当前没有设备连接")
            elif command.startswith('send '):
                parts = command.split(' ', 2)
                if len(parts) >= 3:
                    target_identifier = parts[1]
                    data = parts[2]
                    send_data_to_client(target_identifier, data)
                else:
                    print("用法: send <设备ID或地址> <数据>")
                    print("示例: send 1 01030000000AC5CD")
                    print("示例: send ('127.0.0.1', 12345) 01030000000AC5CD")
                    print("示例: send 1 text:Hello World")
            elif command.startswith('broadcast '):
                data = command[10:]  # 去掉 'broadcast ' 前缀
                if data:
                    broadcast_data_message(data)
                else:
                    print("用法: broadcast <数据>")
                    print("示例: broadcast 01030000000AC5CD")
                    print("示例: broadcast text:Hello World")
            elif command.startswith('test '):
                target_identifier = command[5:].strip()
                if target_identifier:
                    test_command = "01030000000AC5CD"
                    print(f"向设备 {target_identifier} 发送测试命令: {test_command}")
                    send_data_to_client(target_identifier, test_command)
                else:
                    print("用法: test <设备ID或地址>")
                    print("示例: test 1")
                    print("示例: test ('127.0.0.1', 12345)")
            else:
                print("未知命令。输入 'list', 'send', 'broadcast', 'test' 或 'quit'")

        except KeyboardInterrupt:
            print("\n正在关闭服务器...")
            break
        except Exception as e:
            print(f"控制台输入处理错误: {e}")


def hex_string_to_bytes(hex_string):
    """将十六进制字符串转换为字节数据"""
    try:
        # 移除空格和其他分隔符
        hex_string = hex_string.replace(' ', '').replace('-', '').replace(':', '')
        # 确保是偶数长度
        if len(hex_string) % 2 != 0:
            hex_string = '0' + hex_string
        return bytes.fromhex(hex_string)
    except ValueError as e:
        raise ValueError(f"无效的十六进制字符串: {e}")


def parse_data_input(data_input):
    """解析输入的数据，支持文本和十六进制格式"""
    if data_input.startswith('text:'):
        # 文本数据
        text_data = data_input[5:]  # 去掉 'text:' 前缀
        return text_data.encode('utf-8'), 'text', text_data
    else:
        # 尝试解析为十六进制数据
        try:
            byte_data = hex_string_to_bytes(data_input)
            return byte_data, 'hex', data_input
        except ValueError:
            # 如果不是有效的十六进制，当作文本处理
            return data_input.encode('utf-8'), 'text', data_input


def find_client_by_id_or_address(target_identifier):
    """根据客户端ID或地址查找客户端"""
    target_client = None
    target_addr = None
    target_id = None

    # 尝试解析为客户端ID（数字）
    try:
        client_id = int(target_identifier)
        if client_id in client_ids:
            target_addr = client_ids[client_id]
            target_client = clients.get(target_addr)
            target_id = client_id
    except ValueError:
        # 不是数字，按地址查找
        pass

    # 如果按ID没找到，尝试按地址查找
    if target_client is None:
        for addr, client_socket in clients.items():
            if str(addr) == target_identifier or target_identifier in str(addr):
                target_client = client_socket
                target_addr = addr
                target_id = address_to_id.get(addr)
                break

    return target_client, target_addr, target_id


def send_data_to_client(target_identifier, data_input):
    """向指定设备发送数据（支持文本和十六进制，支持ID或地址）"""
    with clients_lock:
        # 查找匹配的客户端
        target_client, target_addr, target_id = find_client_by_id_or_address(target_identifier)

        if target_client:
            try:
                # 解析输入数据
                byte_data, data_type, original_data = parse_data_input(data_input)
                target_client.send(byte_data)

                if data_type == 'hex':
                    print(f"✅ 十六进制数据已发送给设备 [ID: {target_id}] {target_addr}")
                    print(f"   十六进制: {original_data}")
                    print(f"   字节数据: {byte_data}")

                    # 如果是Modbus数据，解析命令
                    if is_modbus_data(byte_data):
                        parsed_cmd = parse_modbus_rtu(byte_data)
                        if "error" not in parsed_cmd:
                            print(f"   Modbus命令: {parsed_cmd['function']}")
                else:
                    print(f"✅ 文本数据已发送给设备 [ID: {target_id}] {target_addr}")
                    print(f"   文本内容: {original_data}")
                    print(f"   字节数据: {byte_data}")

            except Exception as e:
                print(f"❌ 发送数据给设备 [ID: {target_id}] {target_addr} 失败: {e}")
        else:
            print(f"❌ 未找到设备: {target_identifier}")
            print("提示: 可以使用设备ID (如: 1) 或完整地址 (如: ('127.0.0.1', 12345))")


def broadcast_data_message(data_input):
    """向所有设备广播数据（支持文本和十六进制）"""
    with clients_lock:
        if not clients:
            print("❌ 没有设备连接，无法广播消息")
            return

        try:
            # 解析输入数据
            byte_data, data_type, original_data = parse_data_input(data_input)

            disconnected_clients = []
            for addr, client_socket in clients.items():
                try:
                    client_socket.send(byte_data)
                    client_id = address_to_id.get(addr, "未知")
                    print(f"✅ 数据已广播给设备 [ID: {client_id}] {addr}")
                except Exception as e:
                    client_id = address_to_id.get(addr, "未知")
                    print(f"❌ 向设备 [ID: {client_id}] {addr} 广播失败: {e}")
                    disconnected_clients.append(addr)

            if data_type == 'hex':
                print(f"   十六进制: {original_data}")
                print(f"   字节数据: {byte_data}")

                # 如果是Modbus数据，解析命令
                if is_modbus_data(byte_data):
                    parsed_cmd = parse_modbus_rtu(byte_data)
                    if "error" not in parsed_cmd:
                        print(f"   Modbus命令: {parsed_cmd['function']}")
            else:
                print(f"   文本内容: {original_data}")
                print(f"   字节数据: {byte_data}")

            # 移除断开连接的客户端
            for addr in disconnected_clients:
                client_id = address_to_id.get(addr)
                del clients[addr]
                if client_id is not None:
                    del client_ids[client_id]
                    del address_to_id[addr]

        except Exception as e:
            print(f"❌ 广播数据失败: {e}")


def start_tcp_server(host='0.0.0.0', port=9010):
    """启动TCP服务器"""
    # 创建 TCP 套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 允许重用地址

    try:
        # 绑定到指定的 IP 和端口
        server_socket.bind((host, port))

        # 开始监听，最多允许 5 个连接
        server_socket.listen(5)
        print(f"TCP 服务器启动成功，监听 {host}:{port}")

        # 启动控制台输入处理线程
        console_thread = threading.Thread(target=console_input_handler, daemon=True)
        console_thread.start()

        while True:
            try:
                # 等待客户端连接
                client_socket, client_address = server_socket.accept()

                # 为每个客户端创建独立的处理线程
                client_thread = threading.Thread(
                    target=handle_client,
                    args=(client_socket, client_address),
                    daemon=True
                )
                client_thread.start()

            except KeyboardInterrupt:
                print("\n收到中断信号，正在关闭服务器...")
                break
            except Exception as e:
                print(f"接受连接时发生错误: {e}")

    except Exception as e:
        print(f"启动服务器失败: {e}")
    finally:
        # 关闭所有客户端连接
        with clients_lock:
            for client_socket in clients.values():
                try:
                    client_socket.close()
                except:
                    pass
            clients.clear()
            client_ids.clear()
            address_to_id.clear()

        # 关闭服务器套接字
        server_socket.close()
        print("TCP 服务器已关闭")


def start_udp_server(host='0.0.0.0', port=9020):
    """启动UDP服务器"""
    # 创建 UDP 套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 绑定到指定的 IP 和端口
    server_socket.bind((host, port))
    print(f"UDP 服务器启动，监听 {host}:{port} ...")

    while True:
        # 接收数据（缓冲区大小 1024 字节）
        data, client_address = server_socket.recvfrom(1024)
        print(f"收到来自 {client_address} 的消息：{data.decode('utf-8')}")


if __name__ == '__main__':
    print("选择服务器类型:")
    print("1. TCP 服务器 (默认)")
    print("2. UDP 服务器")

    choice = input("请输入选择 (1 或 2): ").strip()

    if choice == '2':
        start_udp_server()
    else:
        start_tcp_server()
